#!/usr/bin/env python
#hmm test

import irc
import string

from commandhandler import CommandHandler
from channels import ChannelManager
import config

import os, sys, time

class bot(irc.Protocol):
    def __init__(self):
        irc.Protocol.__init__(self)
        server, port = config.servers[0].split(":")
        debug = False
        try: debug = config.debug
        except: pass
        debug_file = "log/debug.log"
        try: debug_file = config.debug_file
        except: pass
        self.cmd = CommandHandler(self)
        self.chmgr = ChannelManager(self)
        saddr = None
        try: saddr = config.source_address
        except: pass
        self.connect(server, int(port), config.nicks,
                username=config.username, ircname=config.ircname, version=config.version, debug=debug, debug_log_file=debug_file, source_addr = saddr)
        self.channels = config.channels

        self.loading = []
        self.unloading = []
        self.loaded_plugins = []

        for f in config.plugins:
            if "__init__" in f:
                continue
            
            self._load_plugin(f)

    def get_plugin_name(self, f):
        if "." in f:
            pname = f
        else:
            pname = "plugin." + f

        return pname

    def load_plugin(self, f):
        if f not in self.loading:
            self.loading.append(f)

    def unload_plugin(self, f):
        if f not in self.unloading:
            self.unloading.append(f)

    def rehash_plugin(self, f):
        self.unload_plugin(f)
        self.load_plugin(f)

    def _load_plugin(self, f):
        pname = self.get_plugin_name(f)

        try:
            plugin = __import__(pname, fromlist=[''])
        except (ImportError, ValueError):
            self.logger.info("!@! Could not import: %s" % f)
            plugin = None

        if plugin:
            try:
                self.logger.info("!!! Loading Plugin: %s" % pname)
                plugin.init(self)
                self.loaded_plugins.append(pname)
            except AttributeError:
                self.logger.info("!@! Error loading %s" % pname)
                del sys.modules[pname]
                del sys.modules['plugin'].__dict__[f]
                del plugin

    def _unload_plugin(self, f):
        pname = self.get_plugin_name(f)
        if "." in f:
            f = f[f.rfind('.')+1:]

        try:
            plugin = sys.modules[pname]
        except KeyError:
            return

        try:
            plugin.unload()
        except AttributeError:
            pass
        
        self.logger.info("!!! Unloaded Plugin: %s" % pname)
        self.loaded_plugins.remove(pname)

        del_list = []
        for event in self.cmd.events:
            for handler in self.cmd.events[event]:
                if handler.__module__ == pname:
                    del_list.append((event,handler))

        for e, h in del_list:
            if h in self.cmd.events[e]:
                del self.cmd.events[e][h]

        del sys.modules[pname]
        del sys.modules['plugin'].__dict__[f]
        del plugin

    def check_plugins(self):
        """Handle dynamic plugin loading/unloading"""
        for p in self.unloading:
            self._unload_plugin(p)

        self.unloading = []

        for p in self.loading:
            self._load_plugin(p)

        self.loading = []
 
    def dispatch(self, sender, args):
        self.check_plugins()     
        self.cmd.dispatch(sender, args)

        """This is going to handle things like numeric replies, nickname
        waterfalling and errors. So it's pretty important to call."""
        irc.Protocol.dispatch(self, sender,args)
        self.check_plugins()	# Check plugins after events for control plugins
				# or they won't be loaded until the next event

    def privmsg(self, who, what):
        # Yeah... ugly
        sender = irc.Sender(self, "%s!%s@%s" % \
                (self.nickname, self.username, self.localhost), "")
                
        self.cmd.dispatch(sender, (what, 'PRIVMSG_SELF', who))
        irc.Protocol.privmsg(self, who, what)

    def notice(self, who, what):
        sender = irc.Sender(self, "%s!%s@%s" % \
                (self.nickname, self.username, self.localhost), "")

        self.cmd.dispatch(sender, (what, "NOTICE_SELF", who))
        irc.Protocol.notice(self, who, what)
    
#    def disconnect(self, message):
#        if not self.connected:
#            return
#
#        self.cmd.dispatch(None, ("", "DISCONNECT"))
#        irc.Protocol.disconnect(self, message)
